﻿// Deep Earth is a community project available under the Microsoft Public License (Ms-PL)
// Code is provided as is and with no warranty – Use at your own risk
// View the project and the latest code at http://DeepEarth.codeplex.com/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using DeepEarth.Client.MapControl.Events;

namespace DeepEarth.Client.MapControl
{
    public static class UIElementEx
    {
        public static IObservable<IEvent<DragEventArgs>> GetDragEnter(this UIElement uiElement)
        {
            return Observable.FromEvent<DragEventArgs>(uiElement, "DragEnter");
        }

        public static IObservable<IEvent<DragEventArgs>> GetDragLeave(this UIElement uiElement)
        {
            return Observable.FromEvent<DragEventArgs>(uiElement, "DragLeave");
        }

        
        public static IObservable<IEvent<DragEventArgs>> GetDragOver(this UIElement uiElement)
        {
            return Observable.FromEvent<DragEventArgs>(uiElement, "DragOver");
        }

        public static IObservable<IEvent<DragEventArgs>> GetDrop(this UIElement uiElement)
        {
            return Observable.FromEvent<DragEventArgs>(uiElement, "Drop");
        }

        
        public static IObservable<IEvent<TextCompositionEventArgs>> GetTextInputUpdate(this UIElement uiElement)
        {
            return Observable.FromEvent<TextCompositionEventArgs>(uiElement, "TextInputUpdate");
        }

        public static IObservable<IEvent<TextCompositionEventArgs>> GetTextInputStart(this UIElement uiElement)
        {
            return Observable.FromEvent<TextCompositionEventArgs>(uiElement, "TextInputStart");
        }

        public static IObservable<IEvent<TextCompositionEventArgs>> GetTextInput(this UIElement uiElement)
        {
            return Observable.FromEvent<TextCompositionEventArgs>(uiElement, "TextInput");
        }


        public static IObservable<IEvent<ManipulationStartedEventArgs>> GetManipulationStarted(this UIElement uiElement)
        {
            return Observable.FromEvent<ManipulationStartedEventArgs>(uiElement, "ManipulationStarted");
        }

        public static IObservable<IEvent<ManipulationDeltaEventArgs>> GetManipulationDelta(this UIElement uiElement)
        {
            return Observable.FromEvent<ManipulationDeltaEventArgs>(uiElement, "ManipulationDelta");
        }

        public static IObservable<IEvent<ManipulationCompletedEventArgs>> GetManipulationCompleted(this UIElement uiElement)
        {
            return Observable.FromEvent<ManipulationCompletedEventArgs>(uiElement, "ManipulationCompleted");
        }


        public static IObservable<IEvent<MouseEventArgs>> GetLostMouseCapture(this UIElement uiElement)
        {
            return Observable.FromEvent<MouseEventArgs>(uiElement, "LostMouseCapture");
        }

        public static IObservable<IEvent<RoutedEventArgs>> GetGotFocus(this UIElement uiElement)
        {
            return Observable.FromEvent<RoutedEventArgs>(uiElement, "GotFocus");
        }

        public static IObservable<IEvent<RoutedEventArgs>> GetLostFocus(this UIElement uiElement)
        {
            return Observable.FromEvent<RoutedEventArgs>(uiElement, "LostFocus");
        }



        public static IObservable<IEvent<MouseButtonEventArgs>> GetMouseLeftButtonDown(this UIElement uiElement)
        {
            return Observable.FromEvent<MouseButtonEventArgs>(uiElement, "MouseLeftButtonDown");
        }

        public static IObservable<IEvent<MouseButtonEventArgs>> GetMouseLeftButtonUp(this UIElement uiElement)
        {
            return Observable.FromEvent<MouseButtonEventArgs>(uiElement, "MouseLeftButtonUp");
        }


        public static IObservable<IEvent<MouseButtonEventArgs>> GetMouseRightButtonDown(this UIElement uiElement)
        {
            return Observable.FromEvent<MouseButtonEventArgs>(uiElement, "MouseRightButtonDown");
        }

        public static IObservable<IEvent<MouseButtonEventArgs>> GetMouseRightButtonUp(this UIElement uiElement)
        {
            return Observable.FromEvent<MouseButtonEventArgs>(uiElement, "MouseRightButtonUp");
        }


        public static IObservable<IEvent<KeyEventArgs>> GetKeyUp(this UIElement uiElement)
        {
            return Observable.FromEvent<KeyEventArgs>(uiElement, "KeyUp");
        }

        public static IObservable<IEvent<KeyEventArgs>> GetKeyDown(this UIElement uiElement)
        {
            return Observable.FromEvent<KeyEventArgs>(uiElement, "KeyDown");
        }


        public static IObservable<IEvent<MouseEventArgs>> GetMouseLeave(this UIElement uiElement)
        {
            return Observable.FromEvent<MouseEventArgs>(uiElement, "MouseLeave");
        }

        public static IObservable<IEvent<MouseEventArgs>> GetMouseEnter(this UIElement uiElement)
        {
            return Observable.FromEvent<MouseEventArgs>(uiElement, "MouseEnter");
        }

        public static IObservable<IEvent<MouseEventArgs>> GetMouseMove(this UIElement uiElement)
        {
            return Observable.FromEvent<MouseEventArgs>(uiElement, "MouseMove");
        }

        public static IObservable<IEvent<MouseWheelEventArgs>> GetMouseWheel(this UIElement uiElement)
        {
            return Observable.FromEvent<MouseWheelEventArgs>(uiElement, "MouseWheel");
        }


        // Custom Events
        public static IObservable<MapDragEventArgs> GetMouseDrag(this UIElement uiElement)
        {
           return from pos in GetMouseMove(uiElement)
                       .SkipUntil(GetMouseLeftButtonDown(uiElement))
                       .TakeUntil(GetMouseLeftButtonUp(uiElement))
                       .Let(mm => mm.Zip(mm.Skip(1), (prev, cur) =>
                                    new MapDragEventArgs
                                    {
                                        X1 = prev.EventArgs.GetPosition(uiElement).X,
                                        Y1 = prev.EventArgs.GetPosition(uiElement).Y,
                                        X2 = cur.EventArgs.GetPosition(uiElement).X,
                                        Y2 = cur.EventArgs.GetPosition(uiElement).Y,
                                    })).Repeat()
                   select pos;
        }

        public static IObservable<TimeInterval<IEvent<MouseButtonEventArgs>>> GetDoubleClick(this UIElement uiElement)
        {
            return from dc in GetMouseLeftButtonUp(uiElement).TimeInterval()
                       .Where(click => click.Interval.Milliseconds <= 300)
                   select dc;
        }
    }
}